/**
 * 项目版本编辑接口测试用例
 *
 * Created by snowingsea on 2020/02/13.
 */
const randomstring = require('randomstring');

const chai = require('chai');
const should = chai.should(); // eslint-disable-line no-unused-vars
chai.use(require('chai-http'));

const common = require('./../../common');
const Administrator = require('./../../../models/administrator');
const ProjectVersion = require('./../../../models/project-version');
const uri = require('./../uri');
const { coverageKind } = require('./../../../../phoenix/models/tests');

module.exports = describe('/PUT project-versions/:id.json', function () {
  const administrator = new Administrator();
  let project = {};
  let projectVersion = {};
  const newUserIds = [];
  function url(versionId) {
    if (!versionId) {
      versionId = projectVersion.versionId;
    }
    return `/project-versions/${versionId}.json`;
  }

  before(function (done) {
    administrator.login()
      .then(() => administrator.createRandomTester())
      .then((tester) => {
        newUserIds.push(tester.userId);
        return tester.createRandomProject();
      })
      .then((res) => {
        project = res;
        return project.createRandomVersion();
      })
      .then((res) => {
        projectVersion = res;
        done();
      })
      .catch(done);
  });
  after(function (done) {
    administrator.removeUsers(newUserIds)
      .then(() => {
        done();
      })
      .catch(done);
  });

  common.should.be.user(uri, url, 'put');
  common.should.be.tester(uri, url, 'put');

  // 正常请求编辑
  [
    {},
    { versionName: randomstring.generate(16) },
    { language: ProjectVersion.getRandomProjectVersionInfo().language },
    { projectType: ProjectVersion.getRandomProjectVersionInfo().projectType },
    { headers: { suffixes: [] } },
    { headers: JSON.parse(ProjectVersion.getRandomProjectVersionInfo().headers) },
    { languages: JSON.parse(ProjectVersion.getRandomProjectVersionInfo().languages) },
    { environment: ProjectVersion.getRandomProjectVersionInfo().environment },
    { system: ProjectVersion.getRandomProjectVersionInfo().system },
    { timeout: ProjectVersion.getRandomProjectVersionInfo().timeout },
    { extraExit: randomstring.generate(10) },
    { coverages: ProjectVersion.getRandomProjectVersionInfo().coverages },
    { caseSensitive: Math.random() > 0.5 },
    { systemType: ProjectVersion.getRandomProjectVersionInfo().systemType },
    { strictOutputCheck: Math.random() > 0.5 },
  ].forEach((edit, index) => {
    it(`it should ${index === 0 ? 'PUT' : 'put'} a project version with ${JSON.stringify(edit)}`, function (done) {
      project.creator.login()
        .then(() => {
          chai.request(uri)
            .put(url())
            .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
            // .query(edit)
            .send(edit)
            .end((err, res) => {
              res.should.have.status(200);
              common.should.be.projectVersionMessage(res.body);
              res.body.versionId.should.be.eql(projectVersion.versionId);
              done();
            });
        })
        .catch(done);
    });
  });

  // 修改包含目录以及宏定义
  const keys = ['includes'];
  const data = [];
  [undefined, [], ['c'], ['c', 'd']].forEach((body) => {
    let expected = [];
    if (body) {
      expected = body;
    } else if (body === undefined) {
      expected = undefined;
    }
    data.push({ body, expected });
  });
  keys.forEach((key) => {
    data.forEach((item) => {
      it(`it should put a project version with ${key}: ${JSON.stringify(item)}`, function (done) {
        project.creator.login()
          .then(() => {
            const body = {};
            body[key] = item.body;
            chai.request(uri)
              .put(url())
              .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
              .send(body)
              .end((err, res) => {
                res.should.have.status(200);
                common.should.be.projectVersionMessage(res.body);
                if (item.expected !== undefined) {
                  res.body[key].should.be.eql(item.expected);
                }
                done();
              });
          })
          .catch(done);
      });
    });
  });

  // 编辑项目版本覆盖准则
  [
    { coverages: [coverageKind.statement] },
    { coverages: [coverageKind.branch] },
    { coverages: [coverageKind.mcdc] },
    { coverages: [coverageKind.all] },
    { coverages: [coverageKind.statement | coverageKind.branch] }, // eslint-disable-line no-bitwise
    { coverages: [coverageKind.statement, coverageKind.branch] },
    { coverages: [coverageKind.statement, coverageKind.branch, coverageKind.mcdc] },
  ].forEach((edit) => {
    it(`it should put a project version with ${JSON.stringify(edit)}`, function (done) {
      project.creator.login()
        .then(() => {
          chai.request(uri)
            .put(url())
            .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
            .send({ unitTest: edit })
            .end((err, res) => {
              res.should.have.status(200);
              common.should.be.projectVersionMessage(res.body);
              let expect = 0;
              edit.coverages.forEach((coverage) => {
                expect |= coverage; // eslint-disable-line no-bitwise
              });
              res.body.unitTest.coverages.should.be.eql(expect);
              done();
            });
        })
        .catch(done);
    });
  });

  // macros格式不正确
  it('it should fail to put macros when macros is illegal', function (done) {
    project.creator.login()
      .then(() => {
        chai.request(uri)
          .put(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send({ macros: randomstring.generate(32) })
          .end((err, res) => {
            res.should.have.status(400);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不同项目可存在相同的版本号
  it('it should put same project version to different project', function (done) {
    let newVersionName;
    project.creator.createRandomProject()
      .then((project) => project.createRandomVersion())
      .then(({ versionName }) => {
        newVersionName = versionName;
        return project.creator.login();
      })
      .then(() => {
        chai.request(uri)
          .put(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send({ versionName: newVersionName })
          .end((err, res) => {
            res.should.have.status(200);
            common.should.be.projectVersionMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 由于项目版本号已存在而导致的编辑失败
  it('it should fail to put version\'s versionName when the name is exists', function (done) {
    let newVersionName;
    project.createRandomVersion()
      .then(({ versionName }) => {
        newVersionName = versionName;
        return project.creator.login();
      })
      .then(() => {
        chai.request(uri)
          .put(url())
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send({ versionName: newVersionName })
          .end((err, res) => {
            res.should.have.status(409);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可编辑不存在的项目版本
  it('it should fail to put a project version when the version is not exists', function (done) {
    let projectVersionId;
    project.creator.login()
      .then(() => project.createRandomVersion())
      .then(({ versionId }) => {
        projectVersionId = versionId;
        return project.removeVersion(versionId);
      })
      .then(() => {
        chai.request(uri)
          .put(url(projectVersionId))
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send({ versionName: randomstring.generate(16) })
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 不可编辑他人的项目
  it('it should fail to put a project version when the project is not yours', function (done) {
    administrator.createRandomTester()
      .then((newTester) => {
        newUserIds.push(newTester.userId);
        return newTester.createRandomProject();
      })
      .then((project) => project.createRandomVersion())
      .then(({ versionId }) => {
        chai.request(uri)
          .put(url(versionId))
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send({ versionName: randomstring.generate(16) })
          .end((err, res) => {
            res.should.have.status(404);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 冻结的项目不可编辑版本
  it('it should fail to put a project version when the project is frozen', function (done) {
    let newProjectId;
    let newVersionId;
    project.creator.createRandomProject()
      .then((project) => {
        newProjectId = project.projectId;
        return project.createRandomVersion();
      })
      .then((projectVersion) => {
        newVersionId = projectVersion.versionId;
        return project.creator.freezeProject(newProjectId);
      })
      .then(() => project.creator.login())
      .then(() => {
        chai.request(uri)
          .put(url(newVersionId))
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send({ versionName: randomstring.generate(16) })
          .end((err, res) => {
            res.should.have.status(403);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });

  // 冻结的项目版本不可编辑版本
  it('it should fail to put a project version when the version is frozen', function (done) {
    let newProject;
    let newVersionId;
    project.creator.createRandomProject()
      .then((project) => {
        newProject = project;
        return project.createRandomVersion();
      })
      .then((projectVersion) => {
        newVersionId = projectVersion.versionId;
        return newProject.freezeVersion(newVersionId);
      })
      .then(() => project.creator.login())
      .then(() => {
        chai.request(uri)
          .put(url(newVersionId))
          .set('Authorization', `Bearer ${project.creator.token.accessToken}`)
          .send({ versionName: randomstring.generate(16) })
          .end((err, res) => {
            res.should.have.status(403);
            common.should.be.errorMessage(res.body);
            done();
          });
      })
      .catch(done);
  });
});
